﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Microsoft.PKS;
using System.Runtime.InteropServices;
using System.Web;

namespace UpdateDurationThumbnailHandler
{
    /// <summary>
    /// Calculates duration, filesize, and creates a thumbnail of a 
    /// video file and updates the respective list columns.
    /// </summary>
    public class UpdateDurationThumbnailHandler : SPItemEventReceiver
    {

		#region Member Variables

		private const string pictureLibraryLink = "PKSPictureLibrary";
		
		#endregion

		#region Configuration Properties

		private static class Thumbnail
		{
			private static ManagedConfigList config = null;
			private static SPItemEventProperties props = null;

			public static SPItemEventProperties Props
			{
				get { return props; }
				set
				{
					props = value;
					try
					{
						if (props != null)
						{
							config = new ManagedConfigList(props.OpenWeb());
						}
					}
					catch { }
				}
			}
						  
			public static ManagedConfigList Config
			{
				get { return config; }
			}

			public static Size Size
			{
				get
				{
					if (Config == null) { return new Size(481, 360); }
					return new Size(Config["Thumbnail.Size.Width"].ValueAsInt(481), Config["Thumbnail.Size.Height"].ValueAsInt(360));
				}
			}

			public static double Position
			{
				get
				{
					if (Config == null) { return .27; }
					return Config["Thumbnail.Position"].ValueAsPercent(.27);
				}
			}

			public static bool AllowDistortion
			{
				get
				{
					if (Config == null) { return false; }
					return Config["Thumbnail.AllowDistortion"].ValueAsBool(false);
				}
			}

			public static Color BackgroundColor
			{
				get
				{
					if (Config == null) { return Color.Black; }
					return Config["Thumbnail.BackgroundColor"].ValueAsColor(Color.Black);
				}
			}

			public static string OutputPath
			{
				get
				{
					string ret = "";

					if (Config != null)
					{
						ret = Config["Thumbnail.OutputPath"].Value;
					}

					if (string.IsNullOrEmpty(ret)) { ret = @"C:\AcademyMobile\Thumbnails"; }

					if ((!ret.EndsWith(@"\")) && (!ret.EndsWith("/")))
					{
						string append = @"\";
						if (ret.Contains("/")){append = "/";}
						ret += append;
					}

					return ret;
				}
			}
		}

		public static class ErrorHandling
		{

			public static Bitmap BlankBitmap()
			{
				Bitmap bmp = new Bitmap(Thumbnail.Size.Width, Thumbnail.Size.Height, PixelFormat.Format32bppArgb);
				Graphics g = Graphics.FromImage(bmp);
				g.Clear(Color.Black);
				g.Flush(FlushIntention.Flush);
				g.Dispose();
				return bmp;
			}

			public static class InvalidMediaFile
			{

				public static Bitmap Image
				{
					get
					{
						if (Thumbnail.Config == null) { return BlankBitmap(); }
						SPWeb web = null;
						try
						{
							if (Thumbnail.Props != null) { web = Thumbnail.Props.OpenWeb(); }
						}
						catch { }

						Log("Using Image: " + Thumbnail.Config["ErrorHandling.InvalidMediaFile.Image"].Value);
						Bitmap bmp = GfxUtils.LoadBitmap(Thumbnail.Config["ErrorHandling.InvalidMediaFile.Image"].Value, web);
						if (bmp == null) { return BlankBitmap(); }

						return GfxUtils.HighQualityBitmapResizer.ResizeBitmap(bmp, Thumbnail.Size);
					}
				}
				
				
				public static string Message
				{
					get
					{
						if (Thumbnail.Config == null) { return ""; }
						return Thumbnail.Config["ErrorHandling.InvalidMediaFile.Message"].Value;
					}
				}

				public static GfxUtils.PowerFont Font
				{
					get
					{
						if (Thumbnail.Config == null) { return new GfxUtils.PowerFont("Arial", 20, Color.White, Color.Black, ""); }
						Log("Using Font: " + Thumbnail.Config["ErrorHandling.InvalidMediaFile.Font"].Value);
						return Thumbnail.Config["ErrorHandling.InvalidMediaFile.Font"].ValueAsFont();

						/*string name = "Arial";
						double size = 16;
						Color textColor = Color.Black;
						Color outlineColor = Color.Transparent;
						string style = "bold";

						if (config != null)
						{
							name = config["ErrorHandling.InvalidMediaFile.Font.Name"].Value;
							if (string.IsNullOrEmpty(name)){name = "Arial";}

							size = config["ErrorHandling.InvalidMediaFile.Font.Size"].ValueAsDouble(size);
							textColor = config["ErrorHandling.InvalidMediaFile.Font.ForeColor"].ValueAsColor(textColor);
							outlineColor = config["ErrorHandling.InvalidMediaFile.Font.OutlineColor"].ValueAsColor(outlineColor);
							style = config["ErrorHandling.InvalidMediaFile.Font.Style"].Value;
						}

						return new GfxUtils.PowerFont(name, (float)size, textColor, outlineColor, style);*/
					}
				}
			}

			public static class NoVideoStream
			{

				public static Bitmap Image
				{
					get
					{
						if (Thumbnail.Config == null) { return BlankBitmap(); }
						SPWeb web = null;
						try
						{
							if (Thumbnail.Props != null) { web = Thumbnail.Props.OpenWeb(); }
						}
						catch { }

						Log("Using Image: " + Thumbnail.Config["ErrorHandling.NoVideoStream.Image"].Value);
						Bitmap bmp = GfxUtils.LoadBitmap(Thumbnail.Config["ErrorHandling.NoVideoStream.Image"].Value, web);
						if (bmp == null) { return BlankBitmap(); }

						return GfxUtils.HighQualityBitmapResizer.ResizeBitmap(bmp, Thumbnail.Size);
					}
				}


				public static string Message
				{
					get
					{
						if (Thumbnail.Config == null) { return ""; }
						return Thumbnail.Config["ErrorHandling.NoVideoStream.Message"].Value;
					}
				}

				public static GfxUtils.PowerFont Font
				{
					get
					{
						if (Thumbnail.Config == null) { return new GfxUtils.PowerFont("Arial", 20, Color.White, Color.Black, ""); }
						Log("Using Font: " + Thumbnail.Config["ErrorHandling.NoVideoStream.Font"].Value);
						return Thumbnail.Config["ErrorHandling.NoVideoStream.Font"].ValueAsFont();

						/*string name = "Arial";
						double size = 16;
						Color textColor = Color.Black;
						Color outlineColor = Color.Transparent;
						string style = "bold";

						if (config != null)
						{
							name = config["ErrorHandling.NoVideoStream.Font.Name"].Value;
							if (string.IsNullOrEmpty(name)) { name = "Arial"; }

							size = config["ErrorHandling.NoVideoStream.Font.Size"].ValueAsDouble(size);
							textColor = config["ErrorHandling.NoVideoStream.Font.ForeColor"].ValueAsColor(textColor);
							outlineColor = config["ErrorHandling.NoVideoStream.Font.OutlineColor"].ValueAsColor(outlineColor);
							style = config["ErrorHandling.NoVideoStream.Font.Style"].Value;
						}

						return new GfxUtils.PowerFont(name, (float)size, textColor, outlineColor, style);*/
					}
				}
			}
		}

		#endregion

		#region ItemAdded Handler
		/// <summary>
        /// Calculates duration, creates thumbnails of the primary
        /// file (if video) and updates other list columns when
        /// a new list item gets added.
		/// </summary>
		/// <param name="properties">Item event properties</param>
        public override void ItemAdded(SPItemEventProperties properties)
		{
            if (properties == null)
            {
                throw new ArgumentNullException("properties");
            }

			// Process OBO
			ProcessOBO(properties);

            // Update the duration and thumbnail
            UpdateDurationAndThumbnail(properties);
        }
        #endregion

        #region ItemUpdated Handler
        /// <summary>
        /// Calculates duration, creates thumbnails of the primary
        /// file (if video) and updates other list columns when
        /// a list item gets updated.
        /// </summary>
        /// <param name="properties">Item event properties</param>
        public override void ItemUpdated(SPItemEventProperties properties)
        {
            if (properties == null)
            {
                throw new ArgumentNullException("properties");
            }

			// Process OBO
			ProcessOBO(properties);

            // Update the duration and thumbnail
            UpdateDurationAndThumbnail(properties);
        }
        #endregion

        #region File Processing


		private void SetupConfig(SPItemEventProperties properties)
		{
			Log("Entered SetupConfig.");

			DisableEventFiring();
			Thumbnail.Props = properties;
			EnableEventFiring();

			Log("Leaving SetupConfig.");
		}


		/// <summary>
		/// This function is used for setting the OBO field to true or false, and updating the author field when it is different from the
		/// Created By field, if the person who created the item isn't in the "PKS Impersonators" group, or an administrator.
		/// </summary>
		/// <param name="properties"></param>
		private void ProcessOBO(SPItemEventProperties properties)
		{
			SetupConfig(properties);

			string groupName = "PKS Impersonators";
			try
			{
				groupName = Thumbnail.Config["UploadOnBehalfOf.GroupName"].Value;
			}
			catch { }

			try
			{
				Log("Entered ProcessOBO");

				DisableEventFiring();
				SPListItem item = properties.ListItem;
				SPFieldCollection fields = item.Fields;

				string author, createdBy;
				SPField fAuthor, fCreatedBy;

				author = createdBy = string.Empty;
				fAuthor = fCreatedBy = null;

				fAuthor = RetrieveField(item, "PodcastAuthor");
				if ((fAuthor != null) && (item[fAuthor.Id] != null))
				{ author = item[fAuthor.Id].ToString(); }
				Log("Detected Podcast Author: " + author);

				fCreatedBy = RetrieveField(item, "Author");
				if ((fCreatedBy != null) && (item[fCreatedBy.Id] != null))
				{ createdBy = item[fCreatedBy.Id].ToString(); }
				Log("Detected Created By: " + createdBy);

				bool sendEmail = false;
				if (author != createdBy)
				{
					if (string.IsNullOrEmpty(author))
					{
						item[fAuthor.Id] = item[fCreatedBy.Id];
						author = createdBy;
						Log("Author is blank.");
					}
					else
					{
						bool impersonationOK = false;
						if (IsAdmin(properties, createdBy))
						{
							impersonationOK = true;
							Log("CreatedBy is an administrator (1)");
						}
						else
						{
							SPUser uCreatedBy = GetUser(properties, createdBy);
							if (uCreatedBy != null)
							{
								if (uCreatedBy.IsSiteAdmin)
								{
									impersonationOK = true;
									Log("CreatedBy is an administrator (2)");
								}
								else
								{
									foreach (SPGroup g in uCreatedBy.Groups)
									{
										if (string.Equals(g.Name, groupName, StringComparison.InvariantCultureIgnoreCase))
										{
											Log("CreatedBy is an Impersonator");
											impersonationOK = true;
											break;
										}
									}
								}
							}
						}

						if (!impersonationOK)
						{
							//check credentials
							item[fAuthor.Id] = item[fCreatedBy.Id];
							author = createdBy;
							sendEmail = true;
						}
					}
				}
				item["SendOBONotificationEmail"] = sendEmail;
				item.Update();
			}
			catch (Exception ex)
			{
				Log("ProcessOBO Exception: " + ex.ToString());
				Log("\tStack Trace: " + ex.StackTrace);
			}
			finally
			{
				EnableEventFiring();
			}

			Log("Leaving ProcessOBO");
		}

        /// <summary>
        /// Calculates duration, creates thumbnails of the primary
        /// file (if video) and updates other list columns.
        /// </summary>
        /// <param name="properties">Item event properties</param>
        private void UpdateDurationAndThumbnail(SPItemEventProperties properties)
		{
			try
			{
				SetupConfig(properties);

				Log("entered UpdateDurationAndThumbnail handler");

				DisableEventFiring();

				SPListItem item = properties.ListItem;

				//get path of the file
				//string filePath = GetVideoFilePath(item);

				LfsFileList fileList = new LfsFileList();
				LfsFile primaryFile = null;

				SPField lfsField = RetrieveFieldByType(item, "FilesUpload");
				if (lfsField != null)
				{
					Log("Found Lfs Field: " + lfsField.Title);

					if (item[lfsField.Id] != null)
					{
						string xml = item[lfsField.Id].ToString();
						if (!string.IsNullOrEmpty(xml))
						{
							fileList.LoadXml(xml);
						}
					}

					Log("File List Items: " + fileList.Count.ToString());
					primaryFile = fileList.PrimaryFile;
					if (primaryFile != null)
					{
						Log("Primary Lfs File: " + primaryFile.FileName);
						//Log("Primary Lfs File Resolve Path: " + primaryFile.ResolveServerFileName());
					}
				}
				else
				{
					Log("Could not find Lfs Field.");
				}


				MediaInfo mi = null;

				if (item != null && primaryFile != null)
				{
					try
					{
						Log("inspecting media file");
						mi = new MediaInfo(primaryFile.ResolveServerFileName());
						Log("Media File: \n" + mi.ToString());
					}
					catch { }
				}

				//to do: Check for non media files like doc and ppt files and process appropriately.
				//		 (you can use mi.ValidMediaFile)
				if (item != null)
				{
					Log("item not null.");
					SPFieldCollection fields = item.Fields;
					bool thumbnailColumnExists = false;
					bool needsThumbnail = false;

					Debug.WriteLine("Setting default values...");
					// ---------------------------------------------------------------------------------
					// Set some default values, even if there is NO media file
					// ---------------------------------------------------------------------------------
					foreach (SPField field in fields)
					{
						if (string.Equals(field.Title, "Tags", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("lowercasing tags...");
							string v = string.Empty;
							object o = item["Tags"];

							if (o != null)
							{
								v = o.ToString();
								if (string.IsNullOrEmpty(v)) { v = string.Empty; }
							}
							item["Tags"] = v.ToLower().Trim();
						}
						else if (string.Equals(field.Title, "Duration", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("Resetting duration...");
							item["Duration"] = FormatDuration(0);
						}
						else if (string.Equals(field.Title, "Duration in Seconds", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("Resetting duration in seconds...");
							item["Duration in Seconds"] = 0;
						}
						else if (string.Equals(field.Title, "Size", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("Resetting size...");
							item["Size"] = FormatBytes(0);
						}
						else if (string.Equals(field.Title, "Size in Bytes", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("Resetting size in bytes...");
							item["Size in Bytes"] = 0;
						}
						else if (string.Equals(field.Title, "FileURL", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("Resetting FileUrl...");
							item["FileURL"] = null;
						}
						else if (string.Equals(field.Title, "Thumbnail", StringComparison.InvariantCultureIgnoreCase))
						{
							Debug.WriteLine("Found Thumbnail Column...");
							thumbnailColumnExists = true;

							if (item["Thumbnail"] == null)
							{
								needsThumbnail = true;
							}
							else
							{
								try
								{
									SPFieldUrlValue url = item["Thumbnail"] as SPFieldUrlValue;
									if (string.IsNullOrEmpty(url.Url))
									{
										needsThumbnail = true;
									}
								}
								catch(Exception ex)
								{
									Log("Needs Thumbnail check failed, setting to true: " + ex.ToString());
									needsThumbnail = true;
								}
							}

							Log("Needs new Thumbnail: " + needsThumbnail.ToString());
						}
						else if (string.Equals(field.Title, "Downloads", StringComparison.InvariantCultureIgnoreCase))
						{
							int Downloads = GetDownloadCount(item);
							Debug.WriteLine("Updating Downloads To: " + Downloads.ToString());
							item["Downloads"] = Downloads.ToString();
						}
					}

					Debug.WriteLine("Processing Logic...");
					// ---------------------------------------------------------------------------------
					// Processing logic
					// ---------------------------------------------------------------------------------
					if (mi != null && mi.Exists)
					{
						Log("file exists.");

						//The field.Title checks below might not seem necessary, but they
						// are an easy way to verify that a field exists or hasn't been
						// renamed, and will prevent us from throwing errors while trying
						// to access non-existant fields

						//Log("Calculating the size of the media file: " + );
						//long fileSize = GetFileSizeInBytes(filePath);
						//SPFieldCollection fields = item.Fields;

						foreach (SPField field in fields)
						{
							if (field.Title == "Duration")
							{
								string durationText = FormatDuration(mi.Duration);

								//update duration in list column and update
								Log("updating item with duration: " + durationText);
								item["Duration"] = durationText;
								Log("wrote formatted duration.");
							}

							if (field.Title == "Duration in Seconds")
							{
								item["Duration in Seconds"] = mi.Duration;
								Log("wrote duration in seconds.");
							}

							if (field.Title == "Size in Bytes")
							{
								item["Size in Bytes"] = mi.FileSize;
								Log("wrote size in bytes.");
							}

							if (field.Title == "Size")
							{
								item["Size"] = FormatBytes(mi.FileSize);
								Log("wrote formatted size.");
							}

							if (field.Title == "FileURL")
							{
								Log("FileURL Processing...");
								try
								{
									Guid webId = item.ParentList.ParentWeb.ID;
									Guid listId = item.ParentList.ID;
									string csId = HttpUtility.UrlEncode(webId.ToString() + "@" + listId.ToString());

									string fileURL = item.ParentList.ParentWeb.Url;
									if (!fileURL.EndsWith("/")) { fileURL += "/"; }
									fileURL += "_layouts/MSIT.CustomPages/Download.aspx?csId=" + csId + "&id=" + item.ID.ToString() + "&action=view";

									if (fileURL != null)
									{
										item["FileURL"] = fileURL;
									}
									
								}
								catch(Exception ex)
								{
									Log("Exception thrown while generating download tracking url, generating normal url instead: " + ex.ToString());
									string fileURL = string.Empty;
									fileURL = primaryFile.ClientLink;
									if (fileURL != null)
									{
										item["FileURL"] = fileURL;
									}
								}
							}
						}
					}

					// ---------------------------------------------------------------------------------
					// Update the thumbnail
					// ---------------------------------------------------------------------------------
					if ((thumbnailColumnExists) && ((needsThumbnail) || ((fileList != null) && (fileList.UpdatePrimaryInformation))))
					{
						Bitmap bmp = GenerateThumbnail(mi);
						if (bmp != null)
						{
							Log("Thumbnail generated, attempting to write thumbnail to list.");

							MemoryStream ms = new MemoryStream();
							bmp.Save(ms, ImageFormat.Jpeg);

							byte[] data = new byte[ms.Length];
							Array.Copy(ms.GetBuffer(), data, ms.Length);

							string thumbName = Guid.NewGuid() + ".jpg";
							AddThumbnailToPictureLibrary(properties, data, thumbName);

							SPFieldUrlValue urlValue = new SPFieldUrlValue();
							urlValue.Description = "Automatically Generated Thumbnail at " + DateTime.Now.ToString();
							string url = properties.WebUrl + "/" + pictureLibraryLink + "/" + thumbName;
							urlValue.Url = url;
							Log("updating item with thumbnail");
							item["Thumbnail"] = urlValue;
						}

					}

					Log("Updating Item.");
					item.Update();
					Log("Item Updated.");
				}
			}
			catch(Exception ex)
			{
				Log("UpdateDurationAndThumbnail threw an exception: " + ex.ToString());
			}
			finally
			{
				EnableEventFiring();
				Log("exited UpdateDurationAndThumbnail handler\n");
			}
        }
        #endregion

		#region Helper Functions

		private int GetDownloadCount(SPListItem item)
		{
			try
			{
				SPField DownloadField = RetrieveFieldByType(item, "DownloadItemTracking");
				if (DownloadField == null) { return 0; }

				if (item[DownloadField.Id] == null) { return 0; }
				string o = item[DownloadField.Id].ToString();
				if (string.IsNullOrEmpty(o)) { return 0; }

				string[] seperators = { ";#" };
				string[] vs = o.Split(seperators, int.MaxValue, StringSplitOptions.None);
				if (vs == null) { return 0; }
				if (vs.Length != 4) { return 0; }

				int count = 0;
				int.TryParse(vs[1], out count); //Total Downloads
				//int.TryParse(vs[2], out count); //Unique Downloads
				return count;
			}
			catch { }
			return 0;
		}

		private Bitmap GenerateThumbnail(MediaInfo mi)
		{
			Log("Entering GenerateThumbnail...");
			Bitmap bmp = null;

			try
			{

				if ((mi == null) || (!mi.ValidMediaFile))
				{
					Log("Not a valid media file, generating thumbnail.");
					bmp = ErrorHandling.InvalidMediaFile.Image;
					ErrorHandling.InvalidMediaFile.Font.WriteText(bmp, ErrorHandling.InvalidMediaFile.Message);

					Log("Not a valid media file, generating thumbnail completed.");

					if (bmp != null) { return bmp; }
				}
				else if (!mi.HasVideo)
				{
					Log("Media file does not contain a video stream, generating thumbnail.");

					bmp = ErrorHandling.NoVideoStream.Image;
					ErrorHandling.NoVideoStream.Font.WriteText(bmp, ErrorHandling.NoVideoStream.Message);

					Log("Media file does not contain a video stream, generating thumbnail completed.");

					if (bmp != null) { return bmp; }
				}
				else
				{
					Log("Valid Media File with Video!");
					if (IntPtr.Size == 4) //x86
					{
						Log("32-bit environment detected.");
						try
						{
							bmp = mi.RetrieveThumbnail(Thumbnail.Position * mi.Duration, Thumbnail.Size, Thumbnail.AllowDistortion, Thumbnail.BackgroundColor);
							if (bmp != null) { return bmp; }
						}
						catch (Exception ex)
						{
							Log("\t32-bit Thumbnail Generation Exception Thrown: " + ex.ToString());
						}
					}

					if (bmp == null) //x86 didn't work, or not x86 platform.
					{
						if (IntPtr.Size != 4)
						{
							Log("non 32-bit environment detected, attempting fail-safe method.");
						}
						else
						{
							Log("Unable to get thumbnail using 32-bit method, attempting fail-safe method.");
						}

						try
						{
							if (!Directory.Exists(Thumbnail.OutputPath))
							{ Directory.CreateDirectory(Thumbnail.OutputPath); }

							string fileName = Thumbnail.OutputPath + Guid.NewGuid().ToString() + ".bmp";
							mi.SaveThumbnail(fileName, Thumbnail.Position * mi.Duration, Thumbnail.Size, Thumbnail.AllowDistortion, Thumbnail.BackgroundColor);
							bmp = new Bitmap(fileName);

							//File.Delete(fileName);
						}
						catch (Exception ex)
						{
							Log("\tFail-Safe Thumbnail Generation Exception Thrown: " + ex.ToString());
						}

						if (bmp != null) { return bmp; }
					}
				}
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Exception thrown while generating thumbnail: " + ex.ToString());
				return null;
			}
			finally
			{
				if (bmp == null)
				{
					//Serious issue
					Log("There were serious issues generating a thumbnail for this file. Thumbnail generation aborted.");
				}

				Log("Leaving GenerateThumbnail...");
			}

			return bmp;
		}


		private SPField RetrieveFieldByType(SPItem item, string typeName)
		{
			Log("Entering RetrieveFieldByType, Looking for " + typeName.ToString());
			try
			{
				foreach (SPField field in item.Fields)
				{
					if (string.Equals(field.TypeAsString, typeName, StringComparison.InvariantCultureIgnoreCase))
					{
						return field;
					}
				}
				return null;
			}
			catch
			{ }
			finally
			{
				Log("Leaving RetrieveFieldByType");
			}
			return null;
		}

		private SPField RetrieveField(SPItem item, string internalName)
		{
			foreach (SPField field in item.Fields)
			{
				if (string.Equals(field.InternalName, internalName, StringComparison.InvariantCultureIgnoreCase))
				{
					return field;
				}
			}
			return null;
		}

		private bool IsAdmin(SPItemEventProperties properties, string user)
		{
			Log("Entered IsAdmin");
			int userId = 0;
			if (!user.Contains(";#")) { return false; }
			string[] parts = user.Split(';');
			if (parts == null) { return false; }
			if (parts.Length != 2) { return false; }
			if (!int.TryParse(parts[0], out userId)) { return false; }

			if (userId == 0x3FFFFFFF) { return true; }
			SPUser u = GetUser(properties, user);
			if (u == null) { return false; }

			Log("Leaving IsAdmin");
			return u.IsSiteAdmin;
		}

		private SPUser GetUser(SPItemEventProperties properties, string user)
		{
			Log("Entered GetUser (prop)");

			if (string.IsNullOrEmpty(user)) { return null; }
			if (properties == null) { return null; }
			SPWeb oWebsite = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl);

			Log("leaving GetUser (prop)");
			return GetUser(oWebsite, user);
		}

		private SPUser GetUser(SPWeb oWebsite, string user)
		{
			Log("Entered GetUser (web)");
			if (oWebsite == null) { return null; }

			int userId = 0;
			if (!user.Contains(";#")) { return null; }
			string[] parts = user.Split(';');
			if (parts == null) { return null; }
			if (parts.Length != 2) { return null; }
			if (!int.TryParse(parts[0], out userId)) { return null; }

			try
			{
				return oWebsite.AllUsers[parts[1]];
			}
			catch(Exception)
			{
				Log("Could not find user in oWebsite.AllUsers, attempting manual search.");
			}


			foreach (SPUser u in oWebsite.AllUsers)
			{ if (u.ID == userId) { return u; } }

			Log("Leaving GetUser (web)");

			if (oWebsite.ParentWeb != null)
			{
				return GetUser(oWebsite.ParentWeb, user);
			}

			return null;
		}

		#endregion

        #region Audio and Video Information Routines

		private void AddThumbnailToPictureLibrary(SPItemEventProperties properties, byte[] data, string thumbnailName)
		{
			try
			{
				Log("entering AddThumbnailToPictureLibrary");
				SPWeb web = properties.OpenWeb();
				foreach (SPFolder folder in web.Folders)
				{
					if (string.Equals(folder.Name, pictureLibraryLink, StringComparison.InvariantCultureIgnoreCase))
					{
						folder.Files.Add(folder.Url + "/" + thumbnailName, data, true);
						return;
					}
				}

				Log("Picture Library not found!");
			}
			catch (Exception ex)
			{
				Log("\tAddThumbnailToPictureLibrary threw an exception: " + ex.ToString());
			}
			finally
			{
				Log("exiting AddThumbnailToPictureLibrary");
			}
		}      

        #endregion

        #region Duration and Filesize Formatting Routines
        /// <summary>
        /// Pass in a number of bytes get back a human readable string that
        /// would look something like this: "12.2 KB" or "96.53 MB"
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        static string FormatBytes(long bytes)
        {
            //Sanity Checking:
            if (bytes < 0) { return "0 B"; }

            //I wonder if long has enough precision to even pass in a yotta byte?
            string[] postfix = { " B", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB" };

            //calculate what range this file fits in, most files will be in the "MB" range.
            long temp = bytes;
            decimal mantissa = 0;
            int pfIdx = 0;
            while (temp >= 1024)
            {
                mantissa = (decimal)(temp % 1024);
                mantissa = Math.Round((mantissa / 1024), 2);
                temp /= 1024;
                pfIdx++;
            }

            //return the formatted string
            if (pfIdx >= 0 && pfIdx < postfix.Length)
            {
                decimal output = temp + mantissa;
                return output.ToString() + postfix[pfIdx];
            }

            //will only happen with ridiculously big files, more than likely
            //a bug in the value being passed in, rather than an actual file
            //size
            return bytes.ToString() + " B";
        }
        /// <summary>
        /// Pass in a duration value (in seconds) and get back a human
        /// readable string that would look something like this:
        /// For less than a minute: "52.92 seconds"
        /// For more than a minute: "00:31:25"
        /// </summary>
        /// <param name="duration"></param>
        /// <returns></returns>
        private static string FormatDuration(double duration)
        {
			//if (duration < 60)
			//{
			//    duration = Math.Round(duration, 2);
			//    if (duration == 1) { return "1 second"; }
			//    return duration.ToString() + " seconds";
			//}
            

            TimeSpan ts = new TimeSpan(0, 0, (int)duration);
            return ts.ToString();
        }
        #endregion

		static object o = new object();

		private static void Log(string LogMe)
		{
			Trace.WriteLine(LogMe);

			//lock(o)
			//{
			//    StreamWriter sw = new StreamWriter(@"c:\Documents and Settings\mikej\My Documents\mylog.txt", true, Encoding.UTF8);
			//    sw.WriteLine(DateTime.Now.ToString() + ": " + LogMe);
			//    sw.Flush();
			//    sw.Close();
			//    sw.Dispose();
			//}
		}
    }
}
